import numpy as np

from manim_sandbox.utils.functions.debugTeX import PointIndex
from manimlib import *
from manim_sandbox.utils.mobjects.FuncVectorField import get_vector_field_and_stream_lines


class TestVectorScene(Scene):
    CONFIG = {
        "field_config": {
            "color_by_magnitude": True,
            "magnitude_range": (0.1, 4),
            "arc_len": 3,
        },
        "plane_config": {
            "x_range": [-8, 8],
            "y_range": [-4, 4],
            "height": 8,
            "width": 16,
        },
        "label_height": 3,
        "run_time": 20,
        "slow_factor": 0.25,
    }

    def func(self, x, y):
        return np.dot([[0.9, 0.7], [-0.7, 0.9]], [x, y])

    def construct(self):
        plane = NumberPlane(**self.plane_config)
        plane.add_coordinate_labels()

        vector_field, animated_lines = get_vector_field_and_stream_lines(
            self.func, plane,
            **self.field_config,
        )

        self.add(plane)
        self.add(vector_field)
        self.add(animated_lines)
        self.wait(self.run_time)


class MoveCameraExample(Scene):
    def setup(self):
        self.plane = NumberPlane()
        self.plane.add_coordinate_labels()
        self.add(self.plane)

    def t_func(self, t):
        a, b = 3, 3
        return np.array([
            a * np.cos(t) / t,
            b * np.sin(t) / t,
            0
        ])

    def construct(self):
        frame = self.camera.frame
        curve = ParametricCurve(self.t_func, t_range=[0.1, 300, 0.05], color=YELLOW)
        self.add(curve)
        self.play(
            curve.animate.set_stroke(width=0.3),
            frame.animate.set_width(2).rotate(PI / 2),
            run_time=2
        )
        self.play(
            curve.animate.set_stroke(width=0.05),
            frame.animate.set_width(0.1).rotate(PI / 2),
            run_time=2
        )
        self.wait(0.5)


class AnimatedBoundaryExample(Scene):
    def construct(self):
        text = Text("Hello").scale(4)
        ab = AnimatedBoundary(text, cycle_rate=0.5)
        self.add(text, ab)
        self.play(text.animate.shift(UP))
        self.play(text.animate.shift(LEFT))
        self.play(text.animate.shift(DOWN))
        self.play(text.animate.shift(RIGHT))


class TestAnimateMethod(Scene):
    def construct(self):
        squ = Square()
        self.add(squ)
        anim = squ.animate.shift(UP).scale(2)
        print(anim)
        # turn_animation_into_updater(anim)
        # self.add(squ)
        # self.play(anim)
        # self.wait(2)


class TestAxesNumbers(Scene):
    CONFIG = {
        "axes_config": {
            "x_range": [0, 1.1, 0.1],
            "y_range": [0, 1.1, 0.1],
            "width": 6, "height": 6,
            "x_axis_config": {
                "decimal_number_config": {
                    "num_decimal_places": 1
                },
                "color": BLUE
            },
            "y_axis_config": {
                "decimal_number_config": {
                    "num_decimal_places": 1
                }
            }
        }
    }

    def construct(self):
        axes = Axes(**self.axes_config)
        axes.add_coordinate_labels()
        self.add(axes)


class TestGlowDot(Scene):
    def construct(self):
        center = ORIGIN
        axes = ThreeDAxes()
        self.add(axes)

        # def rgba_func(point: np.ndarray) -> np.ndarray:
        #     return np.array([1, 1, 1, fdiv(1, get_norm(point - center))])

        dot = TrueDot(center=center, radius=3).set_color(WHITE)
        dot.set_color_by_code('''
        color.a = 1.0 / (exp(length(point))) - 0.05;
        ''')
        self.add(dot)


class TestSVG(Scene):
    def construct(self):
        s = SVGMobject("../media/assets/coin__.svg")[0].reverse_points().scale(4)
        s.set_stroke(width=4, color=WHITE)
        s.set_fill(opacity=0.5)
        indexs = PointIndex(s)
        self.add(s)
        self.add(indexs)
        # a = Annulus()
        # indexs = PointIndex(a)
        # self.add(a)
        # self.add(indexs)


class TestWaveSurface(Scene):
    def construct(self):
        A = 1
        omega = PI
        phi = 0
        l = 2

        def wave(u, v):
            return np.array([
                u,
                v,
                A * np.cos(omega * u + phi - TAU / l * v)
            ])

        surface = ParametricSurface(
            wave,
            u_range=(0, 10),
            v_range=(0, 10)
        )
        axes = ThreeDAxes()
        self.add(surface)
        self.add(axes)


class BgText(Text):
    CONFIG = {
        "stroke_width": 6,
        "stroke_color": BLACK,
        "draw_stroke_behind_fill": True
    }


class UnionExample(Scene):
    def construct(self):
        cir1 = Circle(radius=3, color=WHITE, fill_opacity=0.4).move_to(LEFT * 1.5)
        cir2 = cir1.copy().move_to(RIGHT * 1.5)
        u = Union(cir1, cir2, color=YELLOW, fill_opacity=0.4)

        text1 = BgText("cir1").next_to(cir1, UP)
        text2 = BgText("cir2").next_to(cir2, UP)
        textu = BgText("union", fill_color=GOLD).move_to(u.get_center())
        self.add(cir1, cir2, u, text1, text2, textu)


class IntersectionExample(Scene):
    def construct(self):
        cir1 = Circle(radius=3, color=WHITE, fill_opacity=0.4).move_to(LEFT * 1.5)
        cir2 = cir1.copy().move_to(RIGHT * 1.5)
        i = Intersection(cir1, cir2, color=YELLOW, fill_opacity=0.4)

        text1 = BgText("cir1").next_to(cir1, UP)
        text2 = BgText("cir2").next_to(cir2, UP)
        texti = BgText("intersection", fill_color=GOLD).move_to(i.get_center())
        self.add(cir1, cir2, i, text1, text2, texti)


class DifferenceExample(Scene):
    def construct(self):
        cir1 = Circle(radius=3, color=WHITE, fill_opacity=0.4).move_to(LEFT * 1.5)
        cir2 = cir1.copy().move_to(RIGHT * 1.5)
        d = Difference(cir1, cir2, color=YELLOW, fill_opacity=0.4)

        text1 = BgText("submobject").next_to(cir1, UP)
        text2 = BgText("clip").next_to(cir2, UP)
        textd = BgText("difference", fill_color=GOLD).move_to(LEFT * 3)
        self.add(cir1, cir2, d, text1, text2, textd)


class ExclusionExample(Scene):
    def construct(self):
        cirs = VGroup(*[
            Circle(radius=2, fill_opacity=0.1, color=WHITE).move_to(1.5 * np.array([
                np.cos(i / 3 * TAU), np.sin(i / 3 * TAU), 0
            ])) for i in range(3)
        ])
        e = Exclusion(*cirs, color=YELLOW, fill_opacity=0.4)
        text1 = BgText("cirs").next_to(e, RIGHT, buff=0.5).shift(UP / 3)
        text2 = BgText("exclusion", fill_color=GOLD).next_to(e, RIGHT, buff=0.5).shift(DOWN / 3)
        self.add(cirs, e, text1, text2)


class DodecahedronExample(Scene):
    def construct(self):
        d = Dodecahedron(reflectiveness=1.0)
        self.add(d)